#!/usr/bin/env python
# -*- coding: utf-8 -*-
import logging

import cssutils

import PyV8

import w3c
import style

class Render(object):
    logger = logging.getLogger('canvaside.render')

    def __init__(self, soup):
        self.soup = soup
        self.tags = []

    def apply(self):
        class Global(PyV8.JSClass):
            def __init__(self, soup):
                self.document = w3c.DOMImplementation(soup)

            def alert(self, msg):
                print msg

        with PyV8.JSContext(Global(self.soup)) as ctxt:
            self.evalCanvas(ctxt)
            self.evalStyles(ctxt)
            self.evalScripts(ctxt)
            self.evalEvents(ctxt)

        return [tag.contexts.get('2d') for tag in self.tags]

    def evalCanvas(self, ctxt):
        for tag in self.soup.findAll('canvas'):
            self.logger.debug("evaluate canvas : %s", tag)

            tag.styles = []

            if tag.style:
                tag.styles.extend(style.create(cssutils.parseString(tag.style)))

            self.tags.append(tag)

    def evalStyles(self, ctxt):
        for tag in self.soup.findAll('style'):
            sheet = cssutils.parseString(str(tag.string))

            for rule in sheet.cssRules:
                if cssutils.css.CSSRule.STYLE_RULE == rule.type:
                    for selector in rule.selectorList:
                        ns, element = selector.element

                        if element == 'canvas':
                            tags = self.tags

                            self.logger.debug("apply style to all %d canvas tags", len(tags))

                        elif element[0] == '.':
                            classname = selector.element[1:]
                            tags = [tag for tag in self.tags if tag.classname == classname]

                            self.logger.debug("apply style to %d canvas tags with class '%s'", len(tags), classname)

                        elif element[0] == '#':
                            id = selector.element[1:]
                            tags = [tag for tag in self.tags if tag.id == id]

                            self.logger.debug("apply style to %d canvas tags with id '%s'", len(tags), id)

                        else:
                            tags = []

                        map(lambda tag: tag.styles.extend(style.create(rule)), tags)

    def evalScripts(self, ctxt):
        for script in self.soup.findAll('script'):
            if script.has_key('type') and script['type'] not in ['text/javascript', 'application/x-javascript']:
                self.logger.warn("skip script tag with unsupport type: '%s'", script['type'])
            elif script.has_key('src') and script['src']:
                self.logger.warn("skip script tag with external src: '%s'", script['src'])
            else:
                text = str(script.string)
                self.logger.debug("evaluate script : %s", text)
                ctxt.eval(text)

    def evalEvents(self, ctxt):
        events = [tag['onload'] for tag in self.soup.findAll(onload=True)] + \
                 [tag['onerror'] for tag in self.soup.findAll(onerror=True)]

        for event in events:
            text = str(event)
            self.logger.debug("evaluate event: %s", text)
            ctxt.eval(text)

def render(soup):
    return Render(soup).apply()